package com.winning.ds.login.controller;

import com.alibaba.fastjson.JSONObject;
import com.winning.ds.common.controller.BaseController;
import com.winning.ds.common.entity.SysCzjsQxEntity;
import com.winning.ds.common.entity.SysLoginLogEntity;
import com.winning.ds.common.entity.SysQjcsEntity;
import com.winning.ds.common.entity.SysUserEntity;
import com.winning.ds.common.entity.SysZcjgEntity;
import com.winning.ds.common.service.CommonApiService;
import com.winning.ds.common.service.CommonLogApiService;
import com.winning.ds.common.service.TokenService;
import com.winning.ds.common.util.AppContext;
import com.winning.ds.common.util.DateUtil;
import com.winning.ds.common.util.Des3Ces;
import com.winning.ds.common.util.IPUtil;
import com.winning.ds.common.util.ResponseEntity;
import com.winning.ds.common.util.UUIDUtils;
import com.winning.ds.login.service.IndexService;
import com.winning.ds.role.service.SysUserService;
import com.winning.jcpt.sdk.sm4.SM4Utils;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;


/**
 * @Author: nxs@winning.com.cn
 * @Description: 登录相关
 * @Date: 2018-06-20 10:14:24
 **/
@RestController
@Slf4j
public class LoginController extends BaseController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private CommonApiService commonApiService;

    @Autowired
    private IndexService indexService;

    @Autowired
    private CommonLogApiService commonLogApiService;

    @Value("${spring.application.yydm:DQMT}")
    private String YYDM;

    int login_error_count = 0;
    int login_error_time = 0;
    int login_gap_time = 0;

    private static RestTemplate restTemplate = new RestTemplate();


    /**
     * @Author: nxs@winning.com.cn
     * @Description: 登录
     * @Date: 2018-06-20 13:57:58
     * @Param: [username, password, captcha]
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     **/

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Map<String, Object> login(HttpServletRequest request, @RequestParam Map queryParams, String sec, String ticket) throws IOException {

        String username = "";
        String password = "";
        Map<String, String> loginUserMap = AppContext.getInstance().getLoginUserMap();
        SM4Utils sm4Utils = new SM4Utils();

        if (StringUtils.isNotBlank(sec)) {
            try {
                //URL进行了Ecoder处理，解密时，需要做Des3.Decoder处理后，才可以解密
                String result = Des3Ces.decode(sec);
                username = result.split("dldm=")[1].split("&")[0];
                //password = result.split("password=")[1].split("&")[0];
                String dlmm = result.split("dlmm=")[1].split("&")[0];
                password = sm4Utils.encryptData_CBC(dlmm);
            } catch (Exception e) {
                log.error("解密异常:", e);
            }
        } else if (StringUtils.isNotBlank(ticket)) {
            analysisTicket(ticket);
            if (StringUtils.isBlank(analysisTicketUsername)) {
                return ResponseEntity.error("账号或密码不正确");
            }
            username = analysisTicketUsername;
            password = analysisTicketPassword;
        } else {
            username = (String) queryParams.get("username");
            password = (String) queryParams.get("password");
            String tempKey = (String) queryParams.get("tempKey");
            password = sm4Utils.decryptData_CBC(password, tempKey);//先解密非对称的密码
            password = sm4Utils.encryptData_CBC(password);//采用对称的加密

            //当sec和ticket为空时，验证验证码
            String verifycode = (String)queryParams.get("verifycode");
            HttpSession session = request.getSession();
            String sessionId = session.getId();
            if(StringUtils.isEmpty(sessionId) || !verifycode.equalsIgnoreCase((String) session.getAttribute(sessionId))){
                return ResponseEntity.error("验证码校验不正确!");
            }
        }



        //登录结果
        String dljg = "T";
        //用户信息
        SysUserEntity user = sysUserService.selectByUserName(username);

        if (user == null) {   //账号不存在
            dljg = "F";
            return ResponseEntity.error("账号或密码不正确");
        } else if (user != null) {
            //若是超级管理员直接做密码校验，若是非超级管理员进行密码错误次数检验
            if (("2".equals(user.getRylx()) || "超级管理员".equals(user.getRylx())) && !user.getPassword().equals(password)) {   //超级管理员密码错误
                dljg = "F";
                return ResponseEntity.error("账号或密码不正确");
            } else {
                ResponseEntity res = loginLock(user, password);
                //若登录不正常直接返回，若正常则不处理，继续下一步
                if (!res.get("code").toString().equals("200")) {
                    dljg = "F";
                    return res;
                }
            }
        }

        //账号锁定
        if (user.getQyzt().equals("N")) {
            dljg = "F";
            return ResponseEntity.error("账号已被锁定,请联系管理员");
        }
        //判断用户是否登录，若别处登录直接返回   SysQjcsEntity lecEntity
        SysQjcsEntity repeatLoginEntity = commonApiService.queryQjcs("login_permission_repeat");
        String isRepeatLogin = "";
        if (repeatLoginEntity != null) {
            isRepeatLogin = repeatLoginEntity.getCsz();
        }

        if ("false".equals(isRepeatLogin)) {
            boolean isExist = false;
            if (loginUserMap == null) {
                loginUserMap = new HashMap<>();
            }
            for (String usernameHas : loginUserMap.keySet()) {
                //判断是否已经保存该登录用户的信息
                if (!usernameHas.equals(username)) {
                    continue;
                }
                isExist = true;
                break;
            }
        }

        //非超级管理员时，根据是否需要检验密码强度和密码有效期
        if (user != null && !"超级管理员".equals(user.getRylx()) && !"2".equals(user.getRylx())) {
            SysQjcsEntity YXQqjcsEntity = commonApiService.queryQjcs("plat_MMYYQ");
            String yyq = null;
            //数字字母符合两种以上组合
            // ^(?![a-zA-z]+$)(?![0-9]+$)(?![!@#$%^&*]+$)[a-zA-Z0-9!@#$%^&*]+$
            //八位以上数字字母符合两种以上组合
            //^(?![a-zA-z]+$)(?![0-9]+$)(?![!@#$%^&*]+$)[a-zA-Z0-9!@#$%^&*]{8,}$
            if (YXQqjcsEntity != null) {
                yyq = YXQqjcsEntity.getCsz();
            }
            if (yyq != null && !yyq.equals("null") && !yyq.equals("") && !yyq.equals("0")) {
                if (user.getMmxgsj() == null) {
                    dljg = "F";
                    return ResponseEntity.error("密码已过期,请联系管理员");
                } else {
                    Date dateBegin = user.getMmxgsj();
                    Date dateEnd = new Date();
                    long dateDiff = dateEnd.getTime() - dateBegin.getTime();//时间差的毫秒数
                    double dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000));//计算出相差天数
                    if (dayDiff > Integer.parseInt(yyq)) {
                        dljg = "F";
                        return ResponseEntity.error("密码已过期,请联系管理员");
                    }
                }
            }

        }
        loginUserMap.put(username, password);
        //生成token，并保存到数据库
        ResponseEntity re = tokenService.createToken(user.getZclsh());

        //登陆成功后 角色权限 保存到缓存
        List<SysCzjsQxEntity> list = commonApiService.getCzryqx(user.getJgbm(), user.getZclsh(),YYDM);
        //platAdmin不做限制
        if (user != null && CollectionUtils.isEmpty(list)) {
            //账号不存在、密码错误
            dljg = "F";
            return ResponseEntity.error("用户无访问权限");
        }

        Integer zkjgCount = commonApiService.queryZkjgCount();
        if (zkjgCount == 0) {
            return ResponseEntity.error("质控机构未同步");
        }

        Integer zkcsCount = commonApiService.queryZkcsCount();
        if (zkcsCount < 15) {
            return ResponseEntity.error("质控参数未同步");
        }
        //记录登录日志
        SysLoginLogEntity slle = new SysLoginLogEntity();
        slle.setLsh(UUIDUtils.getUUID());
        slle.setDldm(user.getDldm());
        String xm = user.getRyxm();
       /* if (StringUtils.isNotEmpty(xm)) {
            xm = xm.length() > 2 ? xm.substring(0 ,2) + "*" : StringUtils.left(xm, 1) + "*";
        }*/
        slle.setRyxm(xm);
        slle.setDlmm("******");
        slle.setYljgdm(user.getJgbm());
        slle.setRygh(user.getRygh());
        slle.setIp(IPUtil.getIp(request));
        slle.setDlsj(DateUtil.getDate());
        slle.setSsxt("DQMT");
        slle.setYhlx("1");
        slle.setDljg(dljg);
        commonLogApiService.saveLoginLog(slle);

        SysZcjgEntity jgInfo = commonApiService.getJgInfo(user.getJgbm());

        re.put("userName", user.getRyxm());
        re.put("username", user.getDldm());
        re.put("jgbm", user.getJgbm());
        re.put("jgmc", jgInfo.getJgmc());
        re.put("zclsh", user.getZclsh());
        request.getSession().setAttribute("loginUser", user.getDldm());

        SysQjcsEntity showDayJgbm = commonApiService.queryQjcs("sjzk_defaultDisplayDay");
        String showDate = showDayJgbm.getCsz();
        //eidt by dangbo 2021年2月1日15:22:45 根据参数判断当前日期范围
     /* if (StringUtils.length(showDate) < 4) {
        showDate = DateUtil.getCurrentDate("yyyy-MM-dd");
      }*/
        if (!StringUtils.isNotEmpty(showDate)) {
            showDate = DateUtil.getCurrentDate("yyyy-MM-dd");
        } else if ("-1".equals(showDate)) {//前一天
            showDate = DateUtil.getBeforeDaysDate("YYYY-MM-dd", Integer.parseInt(showDate));
        } else if ("-2".equals(showDate)) {//前两天
            showDate = DateUtil.getBeforeDaysDate("YYYY-MM-dd", Integer.parseInt(showDate));
        } else if ("0".equals(showDate)) {//当天
            showDate = DateUtil.getCurrentDate("yyyy-MM-dd");
        }
        re.put("showDate", showDate);
        if (StringUtils.equals(YYDM, "DZBL")) {
            re.put("page", "dzbl-index.html");
        } else {
            re.put("page", "index.html");
        }
        return re;
    }

    public static void main(String[] args) throws Exception {
        String encode = Des3Ces.encode("dldm=platAdmin&dlmm=admin123");
        System.out.println(encode);
    }

    public ResponseEntity loginLock(SysUserEntity user, String password) throws IOException {

        int sbcs = 0;
        Date sdsj = user.getSdsj();
        if (StringUtils.isNotEmpty(user.getSbcs())) {
            sbcs = Integer.parseInt(user.getSbcs());
        }
        //查询参数密码锁定参数
        SysQjcsEntity lecEntity = commonApiService.queryQjcs("login_error_count");
        SysQjcsEntity letEntity = commonApiService.queryQjcs("login_error_time");
        SysQjcsEntity lgtEntity = commonApiService.queryQjcs("login_gap_time");
        if (lecEntity != null && StringUtils.isNotEmpty(lecEntity.getCsz())) {
            login_error_count = Integer.parseInt(lecEntity.getCsz());
        }
        if (letEntity != null && StringUtils.isNotEmpty(letEntity.getCsz())) {
            login_error_time = Integer.parseInt(letEntity.getCsz());
        }
        if (lgtEntity != null && StringUtils.isNotEmpty(lgtEntity.getCsz())) {
            login_gap_time = Integer.parseInt(lgtEntity.getCsz());
        }

        //判断参数是否进行密码错误锁定，不检验直接验证密码
        if (login_error_count != 0 && login_error_time != 0 && login_gap_time != 0) {
            if (sbcs < login_error_count) {
                //开始检验密码
                return verifyPassWord(user, password);
            } else {
                Date sysdate = new Date();
                Date afterDate = new Date(sdsj.getTime() + login_gap_time * 60 * 1000);
                //判断首次密码错误时间是否过期
                if (sysdate.after(afterDate)) {   //已过期,重新计数
                    user.setSbcs("0");
                    indexService.updateUser(user);
                    //开始检验密码
                    return verifyPassWord(user, password);
                } else {
                    int min = (int) (afterDate.getTime() - sysdate.getTime()) / (1000 * 60);
                    min += 1;//添加余数
                    return ResponseEntity.error("用户锁定，请" + min + "分钟后登录");
                }
            }
        } else {
            if (user.getPassword().equals(password)) {   //密码正确
                //登陆成功，更新用户失败次数
                user.setSbcs("0");
                indexService.updateUser(user);
                return ResponseEntity.ok();
            } else {
                return ResponseEntity.error("密码错误");
            }
        }
    }

    private ResponseEntity verifyPassWord(SysUserEntity user, String password) {
        int sbcs = 0;
        Date scmmcwsj = user.getScmmcwsj();
        if (StringUtils.isNotEmpty(user.getSbcs())) {
            sbcs = Integer.parseInt(user.getSbcs());
        }

        if (user.getPassword().equals(password)) {   //密码正确
            //更新用户失败次数
            user.setSbcs("0");
            indexService.updateUser(user);
            return ResponseEntity.ok();
        } else {
            Date sysdate = new Date();
            Date afterDate = new Date(scmmcwsj.getTime() + login_error_time * 60 * 1000);
            //判断首次密码错误时间是否过期
            if (sysdate.after(afterDate)) {   //已过期,重新计数
                user.setSbcs("1");
                user.setScmmcwsj(sysdate);
                indexService.updateUser(user);
                int sycs = login_error_count - 1;
                String msg = "";
                if (sycs > 0) {  //失败次数设为大于两次
                    msg = "密码错误，错误" + sycs + "次即将锁定";
                } else if (sycs == 0) {   //失败次数设为一次
                    msg = "密码错误，用户锁定";
                } else {       //说明没有配置次数校验
                    msg = "密码错误";
                }
                return ResponseEntity.error(msg);
            } else {          //未过期，失败次数加1
                sbcs += 1;
                user.setSbcs(String.valueOf(sbcs));
                if (sbcs < login_error_count) {
                    if (sbcs == 1) {
                        user.setScmmcwsj(sysdate);
                    }
                    indexService.updateUser(user);

                    int sycs = login_error_count - sbcs;
                    return ResponseEntity.error("密码错误，错误" + sycs + "次即将锁定");
                } else {
                    user.setSdsj(new Date());
                    indexService.updateUser(user);
                    return ResponseEntity.error("用户锁定，请" + login_gap_time + "分钟后登录");
                }
            }
        }
    }

    /**
     * @return void
     * @Author zhanglei
     * @Description 注销登录
     * @Date 14:10 2019/8/29
     * @Param [session, userName]
     **/

    @RequestMapping(value = "/logout/{username}", method = RequestMethod.GET)
    public void logout(HttpServletRequest request, @PathVariable String username) {
        //session.invalidate();
        Map<String, String> loginUserMap = AppContext.getInstance().getLoginUserMap();
        if (loginUserMap != null) {
            //loginUserMap.remove(username);
        }
        //从header中获取token
        String token = request.getHeader("token");
        tokenService.deleteBytoken(token);
    }


    private String analysisTicketUsername;
    private String analysisTicketPassword;
    public void analysisTicket(String ticket) {
        // 获取登录token
        SysQjcsEntity sysQjcsEntity = commonApiService.queryQjcs("jcpt_casServer_host");
        JSONObject headJson = new JSONObject();
        headJson.put("ticket", ticket);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json;charset=UTF-8");
        HttpEntity httpEntity = new HttpEntity<String>(headJson.toJSONString(), headers);
        String responseString = restTemplate.postForObject(sysQjcsEntity.getCsz() + "/casServer/appservice/validateService",
                httpEntity, String.class);
        // 获取responseString
        log.info("responseString: " + responseString);
        JSONObject casObject = JSONObject.parseObject(responseString);

        if (200 != casObject.getInteger("code")) {
            log.error("接口调用失败！ url: " + sysQjcsEntity.getCsz() + "/casServer/appservice/validateService; responseString: " + responseString);
            analysisTicketUsername = "";
            return;
        }

        analysisTicketUsername = casObject.getString("username");

        //用户信息
        SysUserEntity user = sysUserService.selectByUserName(analysisTicketUsername);
        analysisTicketPassword = user.getPassword();
    }

}
